在 Android 中使用 eBPF:环境搭建
Editor's Note
维术大佬的第二篇 eBPF 文章
The following article is from 虚拟框架 Author 维术
在 Android 中使用 eBPF:开篇 我们提到,eBPF 在 Android 上有着广泛的用途。但实际上,虽然它在服务端现在红得发紫,但在 Android 上的应用却鲜为人知;并且,由于 eBPF 运行在内核,它对运行环境还有着一定的要求。
目前,eBPF 程序的开发主要有两种:
BCC / bpftrace
bpf CO-RE
BCC / bpftrace
编写 eBPF 程序其实是一件非常头疼的事,因为 Linux 内核不承诺提供稳定的 API,这就导致不同的内核版本各种数据结构以及内核符号都可能不一样,甚至即使是同一份内核代码,开启不同的编译选项和特性,都会导致最终的各种数据结构千差万别。
很久以前,人们解决这个问题的方法是:源代码和编译器一起分发。也就是说,我们在开发机器上写好 eBPF 程序以后,如果要在目标机器上运行,需要在目标机器上装上编译工具链,然后在目标机器上直接编译,得到可以在目标机器上运行的程序。
bpf CO-RE
上面那种“分发编译器”的方式存在着比较大的缺陷,既然我们的 eBPF 有一个虚拟机,那么虚拟机如果能跨平台、跨版本运行那就非常方便了。后来,人们提出了 一种 CO-RE (Compile Once, Run Everywhere) 的技术,与 Java 的口号“一次编写,到处运行”差不多。经过若干年的发展,CO-RE 已经非常接近它的目标了。
在 Android 上运行的难点
然而,上面那两种技术,在 Android 系统上运行都存在较大的问题。
与通常的 Linux 的发行版不同,Android 系统上并没有包管理和软件源,分发编译器的方式在 Android 上很难行得通:我们既没有办法在 Android 系统上直接装个编译器,也很难在 Android 系统上自己构建一个工具链;因为,Android 系统上的软件,都是在其他平台如 macOS / Linux / Windows 上交叉编译的,在 Android 系统上自构建并不被官方支持。
CO-RE 技术不需要分发编译器,可以支持交叉编译,但它的周边工具如 bpftool 都是依赖 Linux 环境的;如果用 ndk 交叉编译不是不可行,但需要自行维护,非常麻烦。
为了解决这个问题,joelagnel 大佬提出了在 Android 上运行 Linux 系统,进而运行 eBPF 工具链的方法,他还开发出了 adeb 的工具开源在 github;这个工具曾经还在 AOSP 官方源码中,不过后来不知什么原因被移除了;个人猜测可能是 CO-RE 技术的兴起,使得这种方式没有那么重要了。
之前我用的也是 adeb 工具,不过遗憾的是,由于它很久不维护,已经不支持 BCC 工具的最新版了;而且由于它的 Debian 系统太老,clang / llvm 工具版本跟不上新的开发工具,已经没有办法直接使用了;我曾经在它上修改了不少 BUG,还给作者提过 PR,不过项目似乎已经没人管。而且,由于它整个项目都是用 bash 脚本写的,维护起来非常麻烦,于是我用 Rust 把它重写了,取名为 eadb。
因此,大家可以使用 eadb 来搭建 eBPF 的开发环境;虽然最终我们会选择使用 CO-RE 技术编写 eBPF 程序,但是,eadb 提供的这个环境,可以让你快速上手,特别是 BCC 提供的一些工具已经足够你解决不少问题了;通过里面的 bpftrace,很多功能可能一行代码就能搞定,在开发阶段验证原型还是很有用的。它的使用方法很简单,直接看 github 的 README 就可以了,项目的地址在这里(阅读原文也可访问):
https://github.com/tiann/eadb
另外,我前几天的直播也演示了这个工具的使用,感兴趣的也可以直接看视频教程:
最后,但愿本文能帮到你,大家晚安!